#include "mp4v2_record.h"
#include <stdlib.h>

NaluQueue g_nalu_queue;
RecorderState g_recorder_state;
volatile int g_main_loop_running = 1; // Controls the main application loop/source

// --- Default Configuration (Example - Ensure it's defined) ---
RecConfig g_config = {
    .segment_duration_sec = 300, // 5 minutes
    .storage_path = ".",         // Current directory
    .queue_size = 1024,          // Queue capacity
    .video_width = 640,          // Example Width
    .video_height = 512,         // Example Height
    .video_fps = 30              // Example FPS
};
// --- End Configuration ---


// --- Queue Implementation (nalu_queue_init, destroy, shutdown, push, pop) ---
// 初始化队列
int nalu_queue_init(NaluQueue* q, int capacity) {
    if (!q || capacity <= 0) return -1;
    q->buffer = (NaluPacket*)malloc(sizeof(NaluPacket) * capacity);
    if (!q->buffer) {
        perror("Failed to allocate NaluQueue buffer");
        return -1;
    }
    q->capacity = capacity;
    q->head = 0;
    q->tail = 0;
    q->count = 0;
    q->shutdown = 0;
    if (pthread_mutex_init(&q->mutex, NULL) != 0) {
        perror("Mutex initialization failed");
        free(q->buffer);
        return -1;
    }
    if (pthread_cond_init(&q->not_empty, NULL) != 0) {
        perror("Condition variable (not_empty) initialization failed");
        pthread_mutex_destroy(&q->mutex);
        free(q->buffer);
        return -1;
    }
    if (pthread_cond_init(&q->not_full, NULL) != 0) {
        perror("Condition variable (not_full) initialization failed");
        pthread_cond_destroy(&q->not_empty);
        pthread_mutex_destroy(&q->mutex);
        free(q->buffer);
        return -1;
    }
    return 0;
}

// 销毁队列 (释放资源)
void nalu_queue_destroy(NaluQueue* q) {
    if (!q) return;
    pthread_mutex_lock(&q->mutex);
    q->shutdown = 1; // Signal threads to exit
    // Free any remaining packets in the buffer
    while (q->count > 0) {
        if (q->buffer[q->tail].data) {
            free(q->buffer[q->tail].data);
        }
        q->tail = (q->tail + 1) % q->capacity;
        q->count--;
    }
    pthread_cond_broadcast(&q->not_empty); // Wake up any waiting consumers
    pthread_cond_broadcast(&q->not_full);  // Wake up any waiting producers
    pthread_mutex_unlock(&q->mutex);

    pthread_mutex_destroy(&q->mutex);
    pthread_cond_destroy(&q->not_empty);
    pthread_cond_destroy(&q->not_full);
    if(q->buffer) free(q->buffer); // Check buffer pointer before freeing
    q->buffer = NULL;
    q->capacity = 0;
}

// 设置队列关闭状态
void nalu_queue_shutdown(NaluQueue* q) {
     if (!q) return;
    pthread_mutex_lock(&q->mutex);
    q->shutdown = 1;
    pthread_cond_broadcast(&q->not_empty); // Wake up consumers
    pthread_cond_broadcast(&q->not_full);  // Wake up producers
    pthread_mutex_unlock(&q->mutex);
}

// 推入 NALU 包 (生产者调用) - data 会被复制
int nalu_queue_push(NaluQueue* q, const uint8_t* data, size_t size, uint64_t pts, int is_keyframe, uint8_t nalu_type) {
    if (!q || !data || size == 0) return -1;

    pthread_mutex_lock(&q->mutex);
    // 等待直到队列不满或收到关闭信号
    while (q->count == q->capacity && !q->shutdown) {
        printf("NaluQueue: Buffer full, waiting...\n");
        // Consider adding a timed wait here (pthread_cond_timedwait)
        // to prevent potential deadlocks if the consumer thread dies unexpectedly.
        pthread_cond_wait(&q->not_full, &q->mutex);
    }

    if (q->shutdown) {
        pthread_mutex_unlock(&q->mutex);
        // printf("NaluQueue: Shutdown signalled during push.\n"); // Reduce verbosity
        return -1; // Indicate shutdown
    }

    // 复制数据
    uint8_t* data_copy = malloc(size);
    if (!data_copy) {
        perror("Failed to allocate memory for NALU copy");
        pthread_mutex_unlock(&q->mutex);
        return -1; // Indicate memory allocation failure
    }
    memcpy(data_copy, data, size);

    // 存储包
    NaluPacket* packet = &q->buffer[q->head];
    packet->data = data_copy;
    packet->size = size;
    packet->pts = pts;
    packet->is_keyframe = is_keyframe;
    packet->nalu_type = nalu_type;

    q->head = (q->head + 1) % q->capacity;
    q->count++;

    // printf("Pushed NALU type %d, size %zu, count %d\n", nalu_type, size, q->count);

    pthread_cond_signal(&q->not_empty); // 通知消费者队列非空
    pthread_mutex_unlock(&q->mutex);
    return 0;
}

// 弹出 NALU 包 (消费者调用)
// 返回 0 成功, -1 队列关闭, -2 错误
int nalu_queue_pop(NaluQueue* q, NaluPacket* packet) {
    if (!q || !packet) return -2;

    pthread_mutex_lock(&q->mutex);
    // 等待直到队列非空或收到关闭信号
    while (q->count == 0 && !q->shutdown) {
        // printf("NaluQueue: Buffer empty, waiting...\n");
        // Consider pthread_cond_timedwait here too.
        pthread_cond_wait(&q->not_empty, &q->mutex);
    }

    if (q->shutdown && q->count == 0) {
        pthread_mutex_unlock(&q->mutex);
        // printf("NaluQueue: Shutdown signalled and queue empty during pop.\n");
        return -1; // Indicate shutdown and queue empty
    }

    // 获取包 (浅拷贝)
    *packet = q->buffer[q->tail]; // Copy struct contents

    // 清理队列中的指针，防止重复释放
    q->buffer[q->tail].data = NULL;
    q->buffer[q->tail].size = 0;

    q->tail = (q->tail + 1) % q->capacity;
    q->count--;

    // printf("Popped NALU type %d, size %zu, count %d\n", packet->nalu_type, packet->size, q->count);

    pthread_cond_signal(&q->not_full); // 通知生产者队列非满
    pthread_mutex_unlock(&q->mutex);
    return 0; // Success
}


// --- MP4 Recorder Module ---

// Helper: 将 Annex B 格式的 NALU 转换为 AVCC 格式 (添加 4 字节长度前缀)
// 返回分配的 AVCC 数据，调用者需要 free()
// 返回 NULL 表示失败
static uint8_t* convert_annexb_to_avcc(const uint8_t* nalu_data, size_t nalu_size, uint32_t* out_avcc_size) {
    if (!nalu_data || nalu_size == 0 || !out_avcc_size) return NULL;

    // 找到 NALU 数据的实际开始位置 (跳过起始码)
    const uint8_t* nalu_start = nalu_data;
    // const uint8_t* end = nalu_data + nalu_size; // Unused variable removed
    size_t start_code_len = 0;
    if (nalu_size >= 4 && nalu_data[0] == 0 && nalu_data[1] == 0 && nalu_data[2] == 0 && nalu_data[3] == 1) {
        nalu_start += 4;
        start_code_len = 4;
    } else if (nalu_size >= 3 && nalu_data[0] == 0 && nalu_data[1] == 0 && nalu_data[2] == 1) {
        nalu_start += 3;
        start_code_len = 3;
    } else {
        // This might be acceptable if the source provides NALUs without start codes
        // For now, assume Annex B input is required by the recorder logic
        fprintf(stderr, "convert_annexb_to_avcc: NALU does not start with a known start code.\n");
        nalu_start = nalu_data;
        start_code_len = 0;
        // If allowing non-AnnexB, this function needs adjustment or bypass.
        // For now, proceed assuming it might be just the payload
        // return NULL; // Or return error if Annex B is mandatory
    }

    uint32_t payload_size = nalu_size - start_code_len;
    if (payload_size == 0) {
        fprintf(stderr, "convert_annexb_to_avcc: NALU payload size is zero.\n");
        return NULL;
    }

    // AVCC 格式: 4 字节长度 + NALU payload
    uint32_t avcc_size = 4 + payload_size;
    uint8_t* avcc_data = malloc(avcc_size);
    if (!avcc_data) {
        perror("Failed to allocate memory for AVCC data");
        return NULL;
    }

    // 写入长度 (网络字节序/大端)
    avcc_data[0] = (payload_size >> 24) & 0xFF;
    avcc_data[1] = (payload_size >> 16) & 0xFF;
    avcc_data[2] = (payload_size >> 8) & 0xFF;
    avcc_data[3] = payload_size & 0xFF;

    // 拷贝 NALU payload
    memcpy(avcc_data + 4, nalu_start, payload_size);

    *out_avcc_size = avcc_size;
    return avcc_data;
}


// 创建新的 MP4 文件并初始化轨道
static int create_new_mp4_file(RecorderState* state) {
    if (!state) return -1;
    int error_occurred = 0; // Changed bool to int, false to 0

    // 确保之前的已关闭 (文件句柄的关闭在 close_and_rename_segment 中完成)
    // pthread_mutex_lock(&state->queue->mutex); // Already locked by caller typically
    if (state->mp4File != MP4_INVALID_FILE_HANDLE) {
        fprintf(stderr, "Warning: create_new_mp4_file called while mp4File is still open (%p).\n", (void*)state->mp4File);
        MP4Close(state->mp4File, 0); // Force close if it wasn't closed properly
        state->mp4File = MP4_INVALID_FILE_HANDLE;
    }
    // pthread_mutex_unlock(&state->queue->mutex);

    // 生成临时文件名 (包含开始时间戳)
    state->segment_start_time = time(NULL);
    snprintf(state->current_filename, sizeof(state->current_filename),
             "%s/%ld_temp.mp4", state->config.storage_path, state->segment_start_time);

    printf("Creating new MP4 file: %s\n", state->current_filename);

    // 创建 MP4 文件
    // Use MP4_CREATE_64BIT_DATA flag for potentially large files
    state->mp4File = MP4CreateEx(state->current_filename, MP4_CREATE_64BIT_DATA, 1, 1, 0, 0, 0, 0);
    if (state->mp4File == MP4_INVALID_FILE_HANDLE) {
        fprintf(stderr, "Error: MP4CreateEx failed for %s\n", state->current_filename);
        error_occurred = 1;
        goto cleanup;
    }

    // 设置时间尺度 (RTSP/RTP 通常使用 90kHz)
    if (!MP4SetTimeScale(state->mp4File, 90000)) {
        fprintf(stderr, "Error: MP4SetTimeScale failed.\n");
        error_occurred = 1;
        goto cleanup;
    }

    // 需要 SPS/PPS 来添加轨道
    if (!state->sps_pps_received) {
        printf("Waiting for SPS/PPS before adding video track...\n");
        // 文件已创建，但无法添加轨道。关闭它，稍后在收到SPS/PPS时，
        // recorder_thread会尝试MP4Modify来重新打开并添加轨道。
        MP4Close(state->mp4File, 0);
        state->mp4File = MP4_INVALID_FILE_HANDLE;
        return 0; // Not an error, but track not added yet
    }

     // 添加 H264 视频轨道 (假设 SPS/PPS 已获取)
     // Ensure SPS data is valid before accessing indices
     if (!state->sps_data || state->sps_size < 4) {
          fprintf(stderr, "Error: Invalid SPS data available when adding video track.\n");
          error_occurred = 1;
          goto cleanup;
     }
    state->videoTrack = MP4AddH264VideoTrack(
        state->mp4File,
        90000, // timescale
        MP4_INVALID_DURATION, // sampleDuration, MP4WriteSample 会计算
        state->config.video_width,
        state->config.video_height,
        state->sps_data[1], // AVCProfileIndication
        state->sps_data[2], // profile_compatibility
        state->sps_data[3], // AVCLevelIndication
        3 // NAL unit length size (4 bytes) - 因为我们用了 convert_annexb_to_avcc
    );

    if (state->videoTrack == MP4_INVALID_TRACK_ID) {
        fprintf(stderr, "Error: MP4AddH264VideoTrack failed.\n");
        error_occurred = 1;
        goto cleanup;
    }

    // 添加 SPS 和 PPS 到轨道配置
    MP4AddH264SequenceParameterSet(state->mp4File, state->videoTrack, state->sps_data, state->sps_size);
    MP4AddH264PictureParameterSet(state->mp4File, state->videoTrack, state->pps_data, state->pps_size);

    // printf("Added H264 video track (ID: %u) with SPS/PPS.\n", state->videoTrack);

    state->first_frame_written = 0; // Changed false to 0
    state->next_pts = 0; // Reset PTS for the new segment

cleanup:
    if (error_occurred && state->mp4File != MP4_INVALID_FILE_HANDLE) {
        MP4Close(state->mp4File, 0);
        state->mp4File = MP4_INVALID_FILE_HANDLE;
        // Optionally delete the partially created temp file?
        // remove(state->current_filename);
    }
    return error_occurred ? -1 : 0;
}

// 关闭当前文件段并重命名
static void close_and_rename_segment(RecorderState* state) {
    // Assumes mutex is held by caller if necessary for state consistency
    if (!state || state->mp4File == MP4_INVALID_FILE_HANDLE) {
        return; // Nothing to close
    }

    printf("Closing MP4 segment: %s\n", state->current_filename);
    MP4FileHandle fileToClose = state->mp4File;
    char old_filename[512];
    strncpy(old_filename, state->current_filename, sizeof(old_filename) - 1);
    old_filename[sizeof(old_filename) - 1] = '\0'; // Ensure null termination
    time_t start_timestamp = state->segment_start_time;

    // Reset state *before* closing, to prevent race conditions if another thread checks state->mp4File
    state->mp4File = MP4_INVALID_FILE_HANDLE;
    state->videoTrack = MP4_INVALID_TRACK_ID;
    state->first_frame_written = 0;
    state->segment_start_time = 0; // Mark segment as finished

    // Now close the file
    MP4Close(fileToClose, 0);

    // Calculate segment duration
    time_t end_time = time(NULL);
    time_t duration = end_time - start_timestamp;

    // Check if duration is less than 3 second
    if (duration < 3) {
        printf("Segment duration (%ld seconds) is less than 3 second. Deleting temporary file: %s\n", (long)duration, old_filename);
        // Delete the temporary file instead of renaming
        if (remove(old_filename) != 0) {
            fprintf(stderr, "Error deleting short segment file %s: %s\n", old_filename, strerror(errno));
        }
    } else {
        // Duration is sufficient, proceed with renaming
        char final_filename[512];
        snprintf(final_filename, sizeof(final_filename), "%s/%ld_%ld.mp4",
                 state->config.storage_path, start_timestamp, end_time);

        // Rename the temporary file
        if (rename(old_filename, final_filename) == 0) {
            printf("File renamed successfully to: %s\n", final_filename);
        } else {
            fprintf(stderr, "Error renaming file %s to %s: %s\n",
                    old_filename, final_filename, strerror(errno));
        }
    }
}


// 检查是否需要分段
static void check_segmentation(RecorderState* state) {
    // Assumes mutex is held by caller
    if (!state || state->mp4File == MP4_INVALID_FILE_HANDLE || state->segment_start_time == 0) {
        return; // Not currently recording a segment
    }

    time_t current_time = time(NULL);
    if (current_time - state->segment_start_time >= state->config.segment_duration_sec) {
        printf("Segment duration reached (%ld >= %d). Closing segment.\n",
               (long)(current_time - state->segment_start_time), state->config.segment_duration_sec);
        close_and_rename_segment(state);
        // The main loop will attempt to create a new file on the next valid frame if recording is enabled
    }
}


// 将 NALU 写入 MP4 文件
static int write_nalu_to_mp4(RecorderState* state, NaluPacket* packet) {
    // Assumes mutex is held by caller
    if (!state || !packet || !packet->data || packet->size == 0) {
        printf("write_nalu_to_mp4: Invalid state or packet.\n");
        return -1;
    }

    if(packet->nalu_type == 6){
        return 0;
    }

    if(packet->nalu_type == 5){
        packet->is_keyframe = 1;
    }

    int need_to_free_avcc = 0; // Changed bool to int, false to 0

     // --- File/Track Readiness Check ---
     // If file not open or track invalid, try to prepare it. This might happen
     // if SPS/PPS arrived after create_new_mp4_file was initially called, or after an error.
    if (state->mp4File == MP4_INVALID_FILE_HANDLE || state->videoTrack == MP4_INVALID_TRACK_ID) {
        if (!state->sps_pps_received) {
            // Still waiting for SPS/PPS, cannot write yet.
            printf("Waiting for SPS/PPS before writing to MP4 file.\n");
            return -2; // Indicate not ready
        }

        // Try to modify existing temp file or create a new one if modify fails
        printf("Attempting to open/modify MP4 file to add track: %s\n", state->current_filename);
        state->mp4File = MP4Modify(state->current_filename, 0);
        if (state->mp4File == MP4_INVALID_FILE_HANDLE) {
            fprintf(stderr, "MP4Modify failed for %s. Attempting MP4CreateEx again.\n", state->current_filename);
            if (create_new_mp4_file(state) != 0) { // create_new_mp4_file handles setting track ID etc.
                fprintf(stderr, "Critical Error: Cannot create/open MP4 file for writing.\n");
                return -1; // Critical failure
            }
            // If create_new_mp4_file succeeded, mp4File and videoTrack should be set (if SPS/PPS received)
            if (state->mp4File == MP4_INVALID_FILE_HANDLE || state->videoTrack == MP4_INVALID_TRACK_ID) {
                 fprintf(stderr, "Error: File/Track still invalid after create attempt.\n");
                 return -1;
            }
        } else {
            // MP4Modify succeeded, now add track if it's not already there (unlikely scenario, but check)
            if(MP4GetNumberOfTracks(state->mp4File, MP4_VIDEO_TRACK_TYPE, 0) == 0) {
                 uint32_t timescale = MP4GetTimeScale(state->mp4File);
                 if (timescale == 0) timescale = 90000;

                  if (!state->sps_data || state->sps_size < 4) {
                       fprintf(stderr, "Error: Invalid SPS data when adding track after MP4Modify.\n");
                       MP4Close(state->mp4File, 0); state->mp4File = MP4_INVALID_FILE_HANDLE;
                       return -1;
                  }

                 state->videoTrack = MP4AddH264VideoTrack(
                       state->mp4File, timescale, MP4_INVALID_DURATION,
                       state->config.video_width, state->config.video_height,
                       state->sps_data[1], state->sps_data[2], state->sps_data[3], 3);

                 if (state->videoTrack != MP4_INVALID_TRACK_ID) {
                      MP4AddH264SequenceParameterSet(state->mp4File, state->videoTrack, state->sps_data, state->sps_size);
                      MP4AddH264PictureParameterSet(state->mp4File, state->videoTrack, state->pps_data, state->pps_size);
                      printf("Video track added successfully after MP4Modify.\n");
                      state->first_frame_written = 0;
                      state->next_pts = 0;
                 } else {
                     fprintf(stderr, "Error: Failed to add video track after MP4Modify.\n");
                     MP4Close(state->mp4File, 0); state->mp4File = MP4_INVALID_FILE_HANDLE;
                     return -1;
                 }
            } else {
                 // Track already exists, find its ID (assuming only one video track)
                 state->videoTrack = MP4FindTrackId(state->mp4File, 0, MP4_VIDEO_TRACK_TYPE, 0);
                 if (state->videoTrack == MP4_INVALID_TRACK_ID) {
                     fprintf(stderr, "Error: Could not find existing video track after MP4Modify.\n");
                     MP4Close(state->mp4File, 0); state->mp4File = MP4_INVALID_FILE_HANDLE;
                     return -1;
                 }
                 printf("Found existing video track ID %u after MP4Modify.\n", state->videoTrack);
            }
        }
    }
     // --- End File/Track Readiness Check ---


    // Wait for keyframe to start a new segment/file
    if (!state->first_frame_written && !packet->is_keyframe) {
        // Keep packet data for buffering in the caller (recorder_thread_func)
        printf("Waiting for keyframe before writing NALU type %d.\n", packet->nalu_type);
        return -2; // Indicate waiting for keyframe
    }

    // Convert Annex B to AVCC format for MP4WriteSample
    uint32_t avcc_size = 0;
    uint8_t* avcc_data = convert_annexb_to_avcc(packet->data, packet->size, &avcc_size);
    if (!avcc_data) {
        fprintf(stderr, "Error converting Annex B to AVCC for NALU type %d.\n", packet->nalu_type);
        return -1; // Conversion error
    }
    need_to_free_avcc = 1; // Changed true to 1 // Mark that we need to free this buffer

    // Calculate sample duration based on configured FPS
    MP4Duration duration = (state->config.video_fps > 0) ? (90000 / state->config.video_fps) : 3000; // Default ~30fps

    // Write the sample
    int success = MP4WriteSample(state->mp4File, state->videoTrack,
                                 avcc_data, avcc_size,
                                 duration, 0, packet->is_keyframe);

    if (need_to_free_avcc) {
        free(avcc_data);
    }

    if (!success) {
        fprintf(stderr, "Error: MP4WriteSample failed for NALU type %d (keyframe: %d).\n", packet->nalu_type, packet->is_keyframe);
        // Consider more robust error handling, e.g., closing the file segment?
        return -1; // Indicate write error
    }

    // Mark that we've successfully written the first frame (if applicable)
    state->first_frame_written = 1; // Changed true to 1
    state->next_pts += duration; // Update expected PTS for potential future use (debugging, precise timing)

    return 0; // Success
}


// --- External Control Function ---

/**
 * @brief Enables or disables MP4 recording. Thread-safe.
 *
 * @param enable True to enable recording, false to disable.
 */
void set_recording_enabled(int enable) {
    // Lock the mutex protecting the shared state (using the queue's mutex here)
    pthread_mutex_lock(&g_recorder_state.queue->mutex);

    if (g_recorder_state.is_recording_enabled != enable) {
        printf("Setting recording state to: %s\n", enable ? "ENABLED" : "DISABLED");
        g_recorder_state.is_recording_enabled = enable;

        // If disabling, the recorder thread itself will handle closing/renaming
        // when it processes the state change in its loop.

        // If enabling, signal the recorder thread in case it was idle/waiting
        // (e.g., waiting on the not_empty condition var). This isn't strictly
        // necessary if it continuously loops, but helps responsiveness.
        if (enable) {
            pthread_cond_signal(&g_recorder_state.queue->not_empty);
        }
    }

    pthread_mutex_unlock(&g_recorder_state.queue->mutex);
}

// Get current recording status
int get_recording_enabled() {
     int status;
     // Use the same mutex for consistent reading
     pthread_mutex_lock(&g_recorder_state.queue->mutex);
     status = g_recorder_state.is_recording_enabled;
     pthread_mutex_unlock(&g_recorder_state.queue->mutex);
     return status;
}

/**
 * @brief 停止录像线程并保存当前录像文件，应在设备重启前调用
 * 
 * @return 0 成功，-1 失败
 */
int stop_recorder_and_save(void) {
    printf("停止录像并保存文件...\n");
    
    // 先禁用录像功能（这会触发关闭当前段）
    set_recording_enabled(0);
    
    // 发送线程终止信号
    pthread_mutex_lock(&g_nalu_queue.mutex);
    g_recorder_state.running = 0;  // 停止录像线程
    pthread_cond_signal(&g_nalu_queue.not_empty); // 唤醒可能等待队列的线程
    pthread_mutex_unlock(&g_nalu_queue.mutex);
    
    // 通知队列已关闭
    nalu_queue_shutdown(&g_nalu_queue);
    
    // 等待录像线程结束
    printf("等待录像线程退出...\n");
    int ret = 0;
    if (pthread_join(g_recorder_state.thread_id, NULL) != 0) {
        fprintf(stderr, "等待录像线程退出失败\n");
        ret = -1;
    } else {
        printf("录像线程已成功退出，文件已保存\n");
    }
    
    return ret;
}


// 录像线程主函数
void* recorder_thread_func(void* arg) {
    RecorderState* state = (RecorderState*)arg;
    if (!state || !state->queue) {
        fprintf(stderr, "Recorder thread error: Invalid state or queue.\n");
        return NULL;
    }
    
    // 检查并创建目录
    if (access(state->config.storage_path, F_OK) != 0) {
        if (errno == ENOENT) {
            if (mkdir( state->config.storage_path, 0755) != 0) {
                perror("Failed to create directory");
                pthread_exit(NULL);
            }
        } else {
            perror("Directory access error");
            pthread_exit(NULL);
        }
    }

    printf("Recorder thread started. Path: %s, Duration: %ds, FPS: %d\n",
           state->config.storage_path, state->config.segment_duration_sec, state->config.video_fps);

    // Initialize state variables
    state->running = 1; // Changed true to 1 // Controls the thread loop itself
    state->mp4File = MP4_INVALID_FILE_HANDLE;
    state->videoTrack = MP4_INVALID_TRACK_ID;
    state->segment_start_time = 0;
    state->first_frame_written = 0; // Changed false to 0
    state->sps_data = NULL;
    state->sps_size = 0;
    state->pps_data = NULL;
    state->pps_size = 0;
    state->sps_pps_received = 0; // Changed false to 0
    state->is_recording_enabled = 0; // Changed false to 0 // Initial recording state

    // Buffer for frames before the first keyframe of a segment
    NaluPacket keyframe_buffer[30]; // Increased buffer size
    int keyframe_buffer_count = 0;
    const int KEYFRAME_BUFFER_CAPACITY = sizeof(keyframe_buffer) / sizeof(keyframe_buffer[0]);

    int currently_recording_segment = 0; // Changed bool to int, false to 0 // Tracks if we are actively writing to a segment

    while (state->running) {
        NaluPacket packet;
        int pop_result = nalu_queue_pop(state->queue, &packet);

        if (pop_result == -1) { // Queue shutdown and empty
            printf("Recorder thread: Queue shutdown signal received and queue empty. Exiting.\n");
            break;
        } else if (pop_result == -2) { // Error during pop
            fprintf(stderr, "Recorder thread: Error popping from queue. Exiting.\n");
            state->running = 0; // Changed false to 0 // Stop thread on critical queue error
            break;
        }
        // printf("Recorder thread: Popped NALU type %d, size %zu, pts:%lu, keyFrame:%d\n", packet.nalu_type, packet.size, packet.pts, packet.is_keyframe);
        // printf("[%02x %02x %02x %02x %02x %02x]", packet.data[0], packet.data[1],  packet.data[2],  packet.data[3],   packet.data[4],  packet.data[5]);

         // pop_result == 0: Successfully popped a packet

        // --- State Management and Decisions (Protected by Mutex) ---
        pthread_mutex_lock(&state->queue->mutex);

        int should_record_now = state->is_recording_enabled;
        int was_recording = currently_recording_segment;

        // --- Handle SPS/PPS (Always process regardless of recording state) ---
        if (packet.nalu_type == 7 /* SPS */ || packet.nalu_type == 8 /* PPS */) {
            // printf("Recorder processing %s NALU (size %zu)\n", (packet.nalu_type == 7 ? "SPS" : "PPS"), packet.size);
            // Extract payload (remove start code) for storing
            const uint8_t* nalu_payload = packet.data;
            size_t nalu_payload_size = packet.size;
            size_t start_code_len = 0;
            if (packet.size >= 4 && packet.data[0] == 0 && packet.data[1] == 0 && packet.data[2] == 0 && packet.data[3] == 1) start_code_len = 4;
            else if (packet.size >= 3 && packet.data[0] == 0 && packet.data[1] == 0 && packet.data[2] == 1) start_code_len = 3;
            nalu_payload += start_code_len;
            nalu_payload_size -= start_code_len;

            if (nalu_payload_size > 0) {
                if (packet.nalu_type == 7) { // SPS
                    if (state->sps_data) free(state->sps_data);
                    state->sps_data = malloc(nalu_payload_size);
                    if (state->sps_data) {
                        memcpy(state->sps_data, nalu_payload, nalu_payload_size);
                        state->sps_size = nalu_payload_size;
                        // printf("  Stored SPS (size %u)\n", state->sps_size);
                    } else { state->sps_size = 0; perror("Failed to store SPS");}
                } else { // PPS
                    if (state->pps_data) free(state->pps_data);
                    state->pps_data = malloc(nalu_payload_size);
                     if (state->pps_data) {
                        memcpy(state->pps_data, nalu_payload, nalu_payload_size);
                        state->pps_size = nalu_payload_size;
                        // printf("  Stored PPS (size %u)\n", state->pps_size);
                    } else { state->pps_size = 0; perror("Failed to store PPS");}
                }
                if (state->sps_data && state->pps_data && !state->sps_pps_received) {
                    state->sps_pps_received = 1;
                    printf("SPS and PPS now available.\n");
                    // If recording is already enabled, we might need to trigger file creation now
                }
            }
            free(packet.data); // Free SPS/PPS packet data
            pthread_mutex_unlock(&state->queue->mutex);
            continue; // Go get next packet
        }


        // --- Recording State Transitions ---
        if (should_record_now && !was_recording) {
            // Transition: Disabled -> Enabled. Try to start recording.
            // printf("Recording enabled. Attempting to start new segment...\n");
            if (state->sps_pps_received) {
                if (create_new_mp4_file(state) == 0) {
                     // File creation successful (or waiting for keyframe)
                     currently_recording_segment = 1; // Changed true to 1 // Mark as trying to record
                    //  printf("New segment initiated (waiting for keyframe if needed).\n");
                } else {
                     fprintf(stderr, "Failed to create initial MP4 file. Recording remains disabled for now.\n");
                     state->is_recording_enabled = 0; // Changed false to 0 // Reset flag if creation failed critically
                     should_record_now = 0; // Changed false to 0 // Don't try to record this frame
                }
            } else {
                printf("Cannot start recording yet: SPS/PPS not received.\n");
                // Keep should_record_now = true, will try again when SPS/PPS arrive or next check
            }
        } else if (!should_record_now && was_recording) {
            // Transition: Enabled -> Disabled. Stop recording.
            printf("Recording disabled. Closing current segment.\n");
            close_and_rename_segment(state); // This also resets state->mp4File etc.
            currently_recording_segment = 0; // Changed false to 0
            // Clear keyframe buffer as the segment is finished
             for (int i = 0; i < keyframe_buffer_count; ++i) {
                 if (keyframe_buffer[i].data) free(keyframe_buffer[i].data);
             }
             keyframe_buffer_count = 0;
        }

        // Re-evaluate after potential state change
        currently_recording_segment = (state->mp4File != MP4_INVALID_FILE_HANDLE);

        // --- Frame Processing Logic ---
        if (should_record_now && state->sps_pps_received) {
            // Recording is enabled and SPS/PPS are available.

            // Check for segmentation time limit
            check_segmentation(state);
            // If segmentation happened, file handle is now invalid, need to restart segment
            if (state->mp4File == MP4_INVALID_FILE_HANDLE && currently_recording_segment) {
                 printf("Segment closed by timer. Attempting to start new segment...\n");
                 currently_recording_segment = 0; // Changed false to 0 // Mark as needing new segment
                 if (create_new_mp4_file(state) == 0) {
                     currently_recording_segment = 1; // Changed true to 1 // Mark as trying again
                     printf("New segment initiated after timer.\n");
                 } else {
                      fprintf(stderr, "Failed to create new MP4 file after timer segment. Recording disabled.\n");
                      state->is_recording_enabled = 0; // Changed false to 0 // Critical error
                      should_record_now = 0; // Changed false to 0
                 }
            }

            // If we are now ready to record (file handle valid)
            if (currently_recording_segment && state->mp4File != MP4_INVALID_FILE_HANDLE) {
                // If we have buffered frames, write them first
                if (keyframe_buffer_count > 0) {
                    // printf("Writing %d buffered frames...\n", keyframe_buffer_count);
                    int buffer_write_error = 0; // Changed bool to int, false to 0
                    int frames_written = 0;
                    for (int i = 0; i < keyframe_buffer_count; ++i) {
                        // Need to ensure we still have a valid file handle after potential errors/segmentation
                        if (state->mp4File == MP4_INVALID_FILE_HANDLE) {
                             fprintf(stderr, "File handle became invalid while writing buffered frames.\n");
                             buffer_write_error = 1; // Changed true to 1
                             // Discard remaining buffered frames?
                             for (int j = i; j < keyframe_buffer_count; ++j) if(keyframe_buffer[j].data) free(keyframe_buffer[j].data);
                             break;
                        }
                        if (write_nalu_to_mp4(state, &keyframe_buffer[i]) == 0) {
                             frames_written++;
                        } else {
                            fprintf(stderr, "Error writing buffered frame %d.\n", i);
                            // If write_nalu failed critically (-1), it might close the file.
                            // If it returned -2 (waiting for keyframe), something is wrong here.
                             buffer_write_error = 1; // Changed true to 1 // Mark error
                             // Discard remaining? Or stop processing? Let's discard rest.
                             for (int j = i; j < keyframe_buffer_count; ++j) if(keyframe_buffer[j].data) free(keyframe_buffer[j].data);
                             break; // Stop processing buffer on error
                        }
                        if(keyframe_buffer[i].data) free(keyframe_buffer[i].data); // Free consumed buffered packet
                    }
                    // printf("Finished writing %d buffered frames.\n", frames_written);
                    keyframe_buffer_count = 0; // Clear buffer count

                    if (buffer_write_error) {
                         fprintf(stderr, "Error occurred during buffered write. Check file state.\n");
                         // Maybe force close and restart segment?
                         if (state->mp4File != MP4_INVALID_FILE_HANDLE) 
                            close_and_rename_segment(state);
                         currently_recording_segment = 0; // Changed false to 0
                         // Discard current packet too?
                         free(packet.data); packet.data = NULL;
                         pthread_mutex_unlock(&state->queue->mutex);
                         continue;
                    }
                }

                // Write the current packet
                int write_result = write_nalu_to_mp4(state, &packet);
                if (write_result == -1) { // Critical write error
                    fprintf(stderr, "Recorder thread: Error writing current NALU. Closing segment.\n");
                    close_and_rename_segment(state);
                    currently_recording_segment = 0; // Changed false to 0
                    // Maybe disable recording on write error?
                    // state->is_recording_enabled = 0;
                } else if (write_result == -2) { // Waiting for keyframe
                    // Buffer this packet if space available
                     // printf("Waiting for keyframe, buffering frame type %d\n", packet.nalu_type);
                     if (keyframe_buffer_count < KEYFRAME_BUFFER_CAPACITY) {
                        keyframe_buffer[keyframe_buffer_count++] = packet;
                        packet.data = NULL; // Prevent double free below
                    } else {
                         printf("Keyframe buffer full while waiting, dropping frame type %d.\n", packet.nalu_type);
                         // Data will be freed below
                    }
                }
                 // write_result == 0 means success, data processed.

            } else {
                 if (keyframe_buffer_count < KEYFRAME_BUFFER_CAPACITY) {
                    keyframe_buffer[keyframe_buffer_count++] = packet;
                    packet.data = NULL; // Prevent double free below
                } else {
                    printf("Keyframe buffer full while file not ready, dropping frame type %d.\n", packet.nalu_type);
                     // Data will be freed below
                }
            }

        } else {
             if (keyframe_buffer_count > 0) {
                // If we were buffering and recording got disabled, clear the buffer
                 printf("Recording disabled, clearing %d buffered frames.\n", keyframe_buffer_count);
                 for (int i = 0; i < keyframe_buffer_count; ++i) {
                     if (keyframe_buffer[i].data) free(keyframe_buffer[i].data);
                 }
                 keyframe_buffer_count = 0;
             }
        }


        // --- Cleanup for the current packet ---
        if (packet.data) {
            free(packet.data); // Free packet data if it wasn't buffered
        }

        pthread_mutex_unlock(&state->queue->mutex);
        // --- End State Management ---

        // Optional small sleep to prevent 100% CPU usage if queue is processed very quickly
        // usleep(1000); // 1ms

    } // end while(state->running)

    printf("Recorder thread: Loop finished.\n");

    // Final cleanup: Ensure the last segment is closed and renamed if recording was active
    pthread_mutex_lock(&state->queue->mutex);
    close_and_rename_segment(state); // Close any open segment
    // Free SPS/PPS
    if (state->sps_data) {
        free(state->sps_data); 
        state->sps_data = NULL;
    }
       
    if (state->pps_data) 
    {
        free(state->pps_data); 
        state->pps_data = NULL;
    }
    // Free any remaining buffered frames (should be empty if logic is correct, but belt-and-suspenders)
    for (int i = 0; i < keyframe_buffer_count; ++i)
        if(keyframe_buffer[i].data) 
            free(keyframe_buffer[i].data);
    pthread_mutex_unlock(&state->queue->mutex);

    printf("Recorder thread finished cleanup.\n");
    return NULL;
}

// --- NALU Parsing and Pushing Logic ---
// Helper to find the next NALU start code (00 00 01 or 00 00 00 01)
// Returns pointer to the start code, or 'end' if not found.
static const uint8_t* find_start_code(const uint8_t* p, const uint8_t* end) {
    while (p <= end - 3) { // Need at least 3 bytes
        if (p[0] == 0 && p[1] == 0) {
            if (p[2] == 1) return p; // Found 00 00 01
            if (p <= end - 4 && p[2] == 0 && p[3] == 1) return p; // Found 00 00 00 01
        }
        p++;
    }
    return end; // Not found
}

// --- External API for Pushing Frames ---
int process_and_push_frame(const uint8_t* frame_data, size_t frame_size, uint64_t frame_pts) {
    // Use the global queue directly
    NaluQueue* q = &g_nalu_queue;

    // Basic validation
    if (!q || !frame_data || frame_size < 4) { // Need at least start code + NALU header byte
         fprintf(stderr, "process_and_push_frame: Invalid arguments (q=%p, frame_data=%p, frame_size=%zu).\n", (void*)q, (void*)frame_data, frame_size);
        return -1;
    }
     // Check if queue is initialized (simple check on capacity)
     // A more robust check might involve a separate 'initialized' flag
    pthread_mutex_lock(&q->mutex);
    int is_q_valid = (q->capacity > 0);
    pthread_mutex_unlock(&q->mutex);
    if(!is_q_valid) {
         fprintf(stderr, "process_and_push_frame: NALU queue is not initialized.\n");
         return -1;
    }

    const uint8_t* p = frame_data;
    const uint8_t* end = frame_data + frame_size;
    const uint8_t* nalu_start = NULL;
    const uint8_t* next_nalu_start = NULL;

    nalu_start = find_start_code(p, end);

    while (nalu_start < end) {
        next_nalu_start = find_start_code(nalu_start + 3, end);
        size_t nalu_size = next_nalu_start - nalu_start;

        const uint8_t* nalu_header_ptr = NULL;
        size_t start_code_len = 0;
        if (nalu_size >= 4 && nalu_start[0] == 0 && nalu_start[1] == 0 && nalu_start[2] == 0 && nalu_start[3] == 1) start_code_len = 4;
        else if (nalu_size >= 3 && nalu_start[0] == 0 && nalu_start[1] == 0 && nalu_start[2] == 1) start_code_len = 3;
        else { /* Invalid start code? Skip */ nalu_start = next_nalu_start; continue; }

        nalu_header_ptr = nalu_start + start_code_len;
        if (nalu_header_ptr >= next_nalu_start) { /* NALU too short? Skip */ nalu_start = next_nalu_start; continue; }

        uint8_t nalu_type = (*nalu_header_ptr) & 0x1F;
        int is_nalu_keyframe = (nalu_type == 5); // Changed bool to int // IDR slice

        if (nalu_queue_push(q, nalu_start, nalu_size, frame_pts, is_nalu_keyframe, nalu_type) != 0) {
            fprintf(stderr, "process_and_push_frame: Failed to push NALU type %d (size %zu) to queue. Aborting frame processing.\n", nalu_type, nalu_size);
            return -1; // Critical error (queue full or shutdown)
        }

        nalu_start = next_nalu_start;
    }

    return 0; // Success
}


// --- Simulation and Main Application ---

// Example function to simulate getting H264 frames
// void simulate_h264_source() {
//     uint64_t pts_counter = 0;
//     int frame_count = 0;
//     uint32_t frame_rate = g_config.video_fps > 0 ? g_config.video_fps : 30;
//     uint64_t pts_increment = 90000 / frame_rate;

//     uint8_t sps_nalu[] = {0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x0a, 0xf8, 0x41, 0xa2};
//     uint8_t pps_nalu[] = {0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x38, 0x80};
//     uint8_t idr_slice_nalu[] = {0x00, 0x00, 0x00, 0x01, 0x65, 0xb8, 0x20, 0x08, 0x00, 0x00};
//     uint8_t p_slice_nalu[] = {0x00, 0x00, 0x00, 0x01, 0x41, 0x9a, 0x4a, 0x2c};

//     size_t buffer_capacity = sizeof(sps_nalu) + sizeof(pps_nalu) + sizeof(idr_slice_nalu) + 100;
//     uint8_t* frame_buffer = malloc(buffer_capacity);
//      if (!frame_buffer) { perror("Simulate: Failed malloc"); g_main_loop_running = 0; return; }

//     printf("Simulating H264 source...\n");
//     printf("Press Enter to toggle recording (starts disabled)...\n");
//     // Start disabled
//     set_recording_enabled(1);


//     while (g_main_loop_running) {
//         // Non-blocking check for user input to toggle recording
//         // This is a simple example, a real application might use a dedicated control mechanism
//          struct timeval tv = { 0L, 0L };
//          fd_set fds;
//          FD_ZERO(&fds);
//          FD_SET(STDIN_FILENO, &fds);
//          if (select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv) > 0) {
//              (void)getchar(); // Consume the newline character
//              int current_status = get_recording_enabled();
//              set_recording_enabled(!current_status);
//          }


//         size_t current_frame_size = 0;
//         memset(frame_buffer, 0, buffer_capacity);

//         int is_key = (frame_count % frame_rate == 0);

//         if (is_key) {
//             // Construct keyframe: SPS + PPS + IDR Slice (optional to include SPS/PPS every time)
//             if (frame_count == 0) { // Send SPS/PPS only on the first keyframe for simulation
//                  memcpy(frame_buffer + current_frame_size, sps_nalu, sizeof(sps_nalu));
//                  current_frame_size += sizeof(sps_nalu);
//                  memcpy(frame_buffer + current_frame_size, pps_nalu, sizeof(pps_nalu));
//                  current_frame_size += sizeof(pps_nalu);
//             }
//             memcpy(frame_buffer + current_frame_size, idr_slice_nalu, sizeof(idr_slice_nalu));
//             current_frame_size += sizeof(idr_slice_nalu);
//         } else {
//             // Construct non-keyframe: P-Slice
//             memcpy(frame_buffer + current_frame_size, p_slice_nalu, sizeof(p_slice_nalu));
//             current_frame_size += sizeof(p_slice_nalu);
//         }

//         // Process the entire frame buffer and push individual NALUs
//         if (process_and_push_frame(frame_buffer, current_frame_size, pts_counter) != 0) {
//              printf("Main loop: Failed to process/push frame. Stopping simulation.\n");
//              g_main_loop_running = 0; // Changed false to 0 // Stop simulation on error
//              break;
//         }

//         pts_counter += pts_increment;
//         frame_count++;

//         usleep(1000000 / frame_rate); // Simulate frame interval

//         // Optional: Stop simulation after some time
//         // if (frame_count > 1000) g_main_loop_running = 0;

//     } // end while

//     free(frame_buffer);
//     printf("Simulated H264 source finished.\n");
//     g_main_loop_running = 0; // Changed false to 0 // Ensure main loop flag is false
//     nalu_queue_shutdown(&g_nalu_queue); // Signal queue shutdown explicitly
// }

// Signal handler for graceful shutdown (e.g., Ctrl+C)
void handle_signal(int sig) {
    // Make signal handlers async-signal-safe if possible
    // Setting recorder state directly might not be safe, rely on queue shutdown
    nalu_queue_shutdown(&g_nalu_queue);
    // write(STDERR_FILENO, "\nShutdown signal received.\n", 26); // Example safe way
}

// Main application entry point
// int main(int argc, char *argv[]) {
//     printf("Starting MP4 Recorder Application...\n");
//     printf("Build time: %s %s\n", __DATE__, __TIME__);

//     // Setup signal handler for graceful exit
//     struct sigaction sa;
//     memset(&sa, 0, sizeof(sa));
//     sa.sa_handler = handle_signal;
//     sigaction(SIGINT, &sa, NULL);
//     sigaction(SIGTERM, &sa, NULL);

//     // 1. Initialize NALU Queue
//     if (nalu_queue_init(&g_nalu_queue, g_config.queue_size) != 0) {
//         fprintf(stderr, "Failed to initialize NALU queue.\n");
//         return 1;
//     }
//     printf("NALU Queue initialized (size %d).\n", g_config.queue_size);

//     // 2. Initialize Recorder State (Shared state setup)
//     memset(&g_recorder_state, 0, sizeof(RecorderState)); // Clear state struct
//     g_recorder_state.queue = &g_nalu_queue;
//     g_recorder_state.config = g_config; // Copy config
//     g_recorder_state.running = 0;   // Changed false to 0 // Thread loop control flag
//     g_recorder_state.is_recording_enabled = 0; // Changed false to 0 // Initial recording state

//     // 3. Create and start Recorder Thread
//     if (pthread_create(&g_recorder_state.thread_id, NULL, recorder_thread_func, &g_recorder_state) != 0) {
//         perror("Failed to create recorder thread");
//         nalu_queue_destroy(&g_nalu_queue);
//         return 1;
//     }
//     printf("Recorder thread created.\n");

//     // 4. Start H264 source simulation
//     simulate_h264_source(); // This blocks until source finishes or g_main_loop_running is false

//     // 5. Wait for recorder thread to finish
//     printf("Waiting for recorder thread to join...\n");
//     // Ensure shutdown signal is sent again in case source finished before signal handler
//     nalu_queue_shutdown(&g_nalu_queue);
//     pthread_join(g_recorder_state.thread_id, NULL); // Wait for recorder thread to exit its loop
//     printf("Recorder thread joined.\n");

//     // 6. Cleanup
//     printf("Cleaning up queue...\n");
//     nalu_queue_destroy(&g_nalu_queue); // Destroy queue after thread has finished using it
//     printf("Cleanup complete. Exiting.\n");

//     return 0;
// }
